package org.chipu.shared.util.singletons;

import java.io.File;
import java.io.InputStream;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class LinuxUtils {
	private static Logger logger = Logger.getLogger(LinuxUtils.class.getName());

	public static void setLogger(Logger l) {
		if (l != null)
			logger = l;
	}

	public static boolean killProcess(String programName) {
		Set<Integer> set = getProcessId(programName);
		if (set.size() == 1) {
			System.out.println("Killing process id: " + set.iterator().next());
			killProcess(set.iterator().next());
			return true;
		}
		System.err.println("Not a single match found using program name '" + programName + "': " + set);
		return false;
	}

	public static boolean isProcessRunning(String programName) {
		return !getProcessId(programName).isEmpty();
	}

	/** @return The list of process ids matched by the programName. */
	public static Set<Integer> getProcessId(String programName) {
		if (!programName.matches("[a-z\\-_0-9]+"))
			throw new IllegalArgumentException("Name not valid: " + programName);
		Process p = runCommand("ps -e | grep " + programName + " | awk '{print $1}'", false, false, true);
		try {
			InputStream is = p.getInputStream();
			byte[] buffer = new byte[1024];
			Set<Integer> set = new HashSet<Integer>();
			for(int count = 0; (count = is.read(buffer)) >= 0;)
				for(String ss : new String(Arrays.copyOf(buffer, count - 1)).split("\\s"))
					set.add(Integer.parseInt(ss));
			return set;
		} catch(Exception ex) {
			logger.log(Level.WARNING, "", ex);
		}
		return Collections.emptySet();
	}

	public static boolean killProcess(int processid) {
		return 0 == runCommand("kill " + processid).exitValue();
	}

	public static Process runCommand(String cmd) {
		return runCommand(cmd, true, true, true);
	}

	public static Process runCommand(String cmd, boolean wait, boolean printStdOut, boolean printErrOut) {
		logger.finer("Executing command \"" + cmd + "\"");
		try {
			String[] command = {"sh", "-c", cmd};
			final Process process = Runtime.getRuntime().exec(command);
			if (printStdOut)
				new Thread() {
					@Override
					public void run() {
						try {
							InputStream is = process.getInputStream();
							byte[] buffer = new byte[1024];
							for(int count = 0; (count = is.read(buffer)) >= 0;)
								logger.finest("\t" + new String(buffer, 0, count - 1));
						} catch(Exception ex) {
							logger.log(Level.WARNING, "", ex);
						}
					}
				}.start();
			if (printErrOut)
				new Thread() {
					@Override
					public void run() {
						try {
							InputStream is = process.getErrorStream();
							byte[] buffer = new byte[1024];
							for(int count = 0; (count = is.read(buffer)) >= 0;)
								logger.warning("\t" + new String(buffer, 0, count - 1));
						} catch(Exception ex) {
							logger.log(Level.WARNING, "", ex);
						}
					}
				}.start();
			if (wait) {
				int returnCode = process.waitFor();
				logger.finer("\tReturn code = " + returnCode);
			}
			return process;
		} catch(Exception ex) {
			logger.log(Level.WARNING, "", ex);
		}
		return null;
	}

	public static boolean createNamedPipe(String pathName, Permissions p) {
		String cmd = "mknod " + ((p == null)? "": ("--mode=" + p + " ")) + pathName + " p";
		return runCommand(cmd, true, false, true).exitValue() == 0;
	}

	public static boolean setGroup(File file, String owner, String group) {
		String cmd = "chown " + owner + ":" + group + " " + file.getAbsolutePath();
		return runCommand(cmd, true, false, true).exitValue() == 0;
	}

	// IMPROVE linux permissions managing
	public static class Permissions {
		public final String s;

		public Permissions(String s) {
			this.s = s;
		}

		@Override
		public String toString() {
			return s;
		}
	}
}